package scaladuct;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: 27.3.11
 * Time: 20:09
 * To change this template use File | Settings | File Templates.
 */
public class SerializableParameterizedType implements ParameterizedType, Serializable {

    private static final long serialVersionUID = -1930021499439149776L;

    private final Type[] actualTypeArguments;
    private final Type rawType;
    private final Type ownerType;

    public SerializableParameterizedType(Class ownerType, Class rawType, Class[] actualTypeArguments) {
        this(actualTypeArguments, ownerType, rawType);
    }

    private SerializableParameterizedType(Type[] actualTypeArguments, Type ownerType, Type rawType) {
        this.actualTypeArguments = actualTypeArguments;
        this.rawType = rawType;
        this.ownerType = ownerType;
    }

    @Override
    public Type[] getActualTypeArguments() {
        return actualTypeArguments;
    }

    @Override
    public Type getRawType() {
        return rawType;
    }

    @Override
    public Type getOwnerType() {
        return ownerType;
    }

    public static Type transform(Type paramType) {
        if (paramType == null)
            return null;
        else if (paramType instanceof Serializable)
            return paramType;
        else if (paramType instanceof ParameterizedType)
            return transformToSerializable((ParameterizedType) paramType);
        else
            throw new IllegalArgumentException("Not serializable type " + paramType);
    }

    private static SerializableParameterizedType transformToSerializable(ParameterizedType paramType) {
        Type[] transformedActualParameters = new Type[paramType.getActualTypeArguments().length];
        for (int i = 0; i < paramType.getActualTypeArguments().length; i++) {
            Type actualParam = paramType.getActualTypeArguments()[i];
            transformedActualParameters[i] = transform(actualParam);
        }

        return new SerializableParameterizedType(
                transformedActualParameters,
                transform(paramType.getOwnerType()),
                transform(paramType.getRawType()));
    }
}
